package com.kamistoat.meimeimall.meimeimallsearch.service.Impl;

import com.alibaba.fastjson.JSON;
import com.kamistoat.meimeimall.common.To.EsTo.RegisterUpTo;
import com.kamistoat.meimeimall.common.To.EsTo.SpuUpTo;
import com.kamistoat.meimeimall.common.exception.BizCodeEnum;
import com.kamistoat.meimeimall.common.exception.RRException;
import com.kamistoat.meimeimall.meimeimallsearch.config.ElasticSearchConfig;
import com.kamistoat.meimeimall.common.constant.SearchConstant;
import com.kamistoat.meimeimall.meimeimallsearch.service.ElasticSaveService;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.List;

@Slf4j
@Service
public class ElasticSaveServiceImpl implements ElasticSaveService {

    // 自动注入client，操作ES都需要这个类
    @Autowired
    RestHighLevelClient restHighLevelClient;

    /**
     * 在spu上架时，将spu下的一系列sku信息保存到ES中
     *
     * @param spuUpToList spuUpTo列表
     */
    @Override
    public void spuUpToES(List<SpuUpTo> spuUpToList) throws IOException {
        // 批量保存bulk要用BulkRequest库类
        BulkRequest bulkRequest = new BulkRequest(SearchConstant.PRODUCT_INDEX);
        // 循环向bulkRequest中添加数据
        for (SpuUpTo spuUpTo : spuUpToList) {
            // BulkRequest中还是要放IndexRequest库类
            IndexRequest indexRequest = new IndexRequest(SearchConstant.PRODUCT_INDEX);  // 新建IndexRequest库类
            indexRequest.id(spuUpTo.getSkuId().toString());  // 唯一标识正好就设定为商品SkuId，不过要记得转换成String数据类型
            String jsonString = JSON.toJSONString(spuUpTo);  // 同样是转换成JSON
            indexRequest.source(jsonString, XContentType.JSON);
            bulkRequest.add(indexRequest);  // 直接使用add将index请求添加到bulk请求中
        }
        BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, ElasticSearchConfig.COMMON_OPTIONS);
        // 返回的bulk包含多个结果，批量执行了多少个index，就会有多少个结果
        boolean error = bulk.hasFailures();  // 直接获取错误信息，如果有错 error=true
        if (error) {
            // TODO 如果bulk出现错误，可以处理这个错误
            throw new RRException(bulk.buildFailureMessage(), BizCodeEnum.ES_INDEX_EXCEPTION.getCode());
        }
    }

    /**
     * 在spu下架时，将spu下的一系列sku信息从ES中删除
     *
     * @param skuIdList skuId列表
     */
    @Override
    public void spuDownToES(List<Long> skuIdList) throws IOException {
        // 要批量删除，用bulk请求
        BulkRequest bulkRequest = new BulkRequest(SearchConstant.PRODUCT_INDEX);
        for (Long skuId : skuIdList) {
            // 从ES中对每一个skuID执行删除
            DeleteRequest deleteRequest = new DeleteRequest(SearchConstant.PRODUCT_INDEX);
            deleteRequest.id(skuId.toString());
            bulkRequest.add(deleteRequest);
        }
        // 获取批量操作的返回结果
        BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, ElasticSearchConfig.COMMON_OPTIONS);
        boolean error = bulk.hasFailures();  // 直接获取错误信息，如果有错 error=true
        if (error) {
            // TODO 如果bulk出现错误，可以处理这个错误
            throw new RRException(bulk.buildFailureMessage(), BizCodeEnum.ES_INDEX_EXCEPTION.getCode());
        }
    }

    /**
     * 注册时将用户名和手机号保存到ES
     *
     * @param registerUpTo To
     */
    @Override
    public void registerUpToEs(RegisterUpTo registerUpTo) throws IOException {
        IndexRequest indexRequest = new IndexRequest(SearchConstant.REGISTER_INDEX);  // 新建IndexRequest库类
        String jsonString = JSON.toJSONString(registerUpTo);  // 同样是转换成JSON
        indexRequest.source(jsonString, XContentType.JSON);
        restHighLevelClient.index(indexRequest, ElasticSearchConfig.COMMON_OPTIONS);
    }

    /**
     * 前端直接访问，查看注册时是否重名
     *
     * @param username username
     * @return 是否重名
     */
    @Override
    public Boolean usernameUniqueES(String username) throws IOException {
        // 首先要创建一个检索请求库类SearchRequest
        SearchRequest searchRequest = new SearchRequest(SearchConstant.REGISTER_INDEX);  // 也可以searchRequest.indices()
        // 使用SearchSourceBuilder库类来构建检索条件
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        // must查询里是一个match查询，因此构建这个match
        MatchQueryBuilder usernameMatch = new MatchQueryBuilder("username", username);
        // 把这个match放到bool.must中
        boolQueryBuilder.must(usernameMatch);
        searchSourceBuilder.query(boolQueryBuilder);
        searchRequest.source(searchSourceBuilder);
        SearchResponse usernameResponseES =
                restHighLevelClient.search(searchRequest, ElasticSearchConfig.COMMON_OPTIONS);
        long totalHit = usernameResponseES.getHits().getTotalHits().value;
        return totalHit != 0L;
    }
}
